package com.taldh.springdata.config;

import com.taldh.springdata.dao.JpaTemplate;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

import java.util.HashSet;
import java.util.Set;

public class JpaScanner extends ClassPathScanningCandidateComponentProvider {

    private boolean considerNestedRepositoryInterfaces;
    private final BeanDefinitionRegistry registry;

    public JpaScanner(Iterable<? extends TypeFilter> includeFilters, BeanDefinitionRegistry registry) {

        super(false);

        Assert.notNull(includeFilters, "Include filters must not be null!");
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");

        this.registry = registry;

        if (includeFilters.iterator().hasNext()) {
            for (TypeFilter filter : includeFilters) {
                addIncludeFilter(filter);
            }
        } else {
            //dao 过滤器，要继承了BaseBizEsDao，或者BaseEsDao的类才行。
            super.addIncludeFilter(new AssignableTypeFilter(JpaTemplate.class));
            super.addExcludeFilter(new ClassExcludeFilter(JpaTemplate.class));
        }

    }

    /**
     * dao 过滤器，要继承了BaseBizEsDao，或者BaseEsDao的类才行。
     */
    @Override
    public void addIncludeFilter(@NonNull TypeFilter includeFilter) {
        super.addIncludeFilter(includeFilter);
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return true;
    }

    /**
     * Customizes the repository interface detection and triggers annotation detection on them.
     */
    @Override
    @NonNull
    public Set<BeanDefinition> findCandidateComponents(@NonNull String basePackage) {
        return super.findCandidateComponents(basePackage);
    }

    @Override
    protected BeanDefinitionRegistry getRegistry() {
        return registry;
    }

    /**
     * 去掉针对的class
     */
    private static class ClassExcludeFilter extends AbstractTypeHierarchyTraversingFilter {
        private final Set<String> classNames = new HashSet<>();

        ClassExcludeFilter(Object... sources) {
            super(false, false);
            for (Object source : sources) {
                if (source instanceof Class<?>) {
                    this.classNames.add(((Class<?>) source).getName());
                }
            }
        }

        protected boolean matchClassName(@NonNull String className) {
            return this.classNames.contains(className);
        }
    }

}
